A filter can perform its side effect (auditing, metrics) and then re-throw the exception using throw exception. Because filter resolution goes method → controller → global, the re-thrown exception propagates to the next wider-scoped filter that matches it. This pattern enables composable single-responsibility filters.
Single responsibility — the audit filter only audits; the global filter only sends responses.
No duplication of response logic across multiple filters.
Re-thrown exceptions follow the same method -> controller -> global resolution path.
Narrow filters can choose to handle some exceptions and re-throw others based on the status code.
This pattern is composable — add or remove audit behavior without touching the response filter.